﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.ServiceModel;
using DotNETX.CommonWcfClient;

namespace DotNETX.CommonWcfHost.Manager
{
    public partial class MainForm : Form
    {
        public const int MAX_CONTINUAL_ERR_COUNT = 3;

        CommonClient<DotNETX.CommonWcfHost.ICommonHostController> controllerClient = null;
        CommonHost commonSvcHost = null;

        string configKeyServiceName = "HostName";
        string configKeyDescription = "Description";
        string configKeyAutoOpen = "AutoStartAllService";
        string configKeyAssemblyFolders = "ServiceAssemblyFolders";
        string configKeyControllerPort = "ControllerPort";
        string configKeyWindowsServiceAssemblyFilePath = "WindowsServiceAssemblyLocation";

        string serviceName = null;
        string description = null;

        public Dictionary<string, int> errCounts = new Dictionary<string, int>();
        bool exitFlag = false;
        bool _hostInSvcStartedFlag = false;
        bool HostInServiceInstalledFlag
        {
            get
            {
                return InstalUtil.IsServiceExisted(serviceName);
            }
        }
        bool HostInServiceStartedFlag
        {
            get
            {
                return _hostInSvcStartedFlag;
            }
            set
            {
                _hostInSvcStartedFlag = value;
                if (value) this.Text = serviceName + " - Windows Service";
                else this.Text = serviceName;
            }
        }

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            serviceName = ConfigurationManager.AppSettings[configKeyServiceName];
            description = ConfigurationManager.AppSettings[configKeyDescription];
            if (null != serviceName) this.Text = serviceName;
            if (null != description) this.notifyIcon1.Text = description;


            bool autostart = AutoStartService;
            if (autostart)
            {
                toolStripButton1.Checked = true;
            }
            toolStrip1.Enabled = false;

            if (HostInServiceInstalledFlag)
            {
                btnInstallWinSvc.Visible = false;
            }
            else
            {
                btnUnInstallWinSvc.Visible = false;
            }

            this.Text += " - Loading";
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += (s, a) =>
            {
                OpenController4WinServiceHost();
                OpenCommonServiceHost();

                try
                {
                    if (HostInServiceInstalledFlag)
                    {
                        controllerClient.Proxy.GetServiceNames();
                        a.Result = true;
                    }
                    else
                    {
                        a.Result = false;
                    }
                }
                catch
                {
                    a.Result = false;
                }
                if (autostart)
                {
                    _hostInSvcStartedFlag = (bool)a.Result;
                    HostController.OpenAll();
                }

            };
            bw.RunWorkerCompleted += (s, a) =>
            {
                HostInServiceStartedFlag = (bool)a.Result;
                LoadServiceList();
                toolStrip1.Enabled = true;
            };
            bw.RunWorkerAsync();
        }

        private bool AutoStartService
        {
            get
            {
                string strAutoStart = System.Configuration.ConfigurationManager.AppSettings[configKeyAutoOpen];
                if (null != strAutoStart && ("true,yes,1").Split(',').Contains(strAutoStart.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            set
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

                if (null != config.AppSettings.Settings[configKeyAutoOpen])
                {
                    config.AppSettings.Settings[configKeyAutoOpen].Value = value.ToString();
                }
                else
                {
                    config.AppSettings.Settings.Add(configKeyAutoOpen, value.ToString());
                }
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("appSettings");
            }
        }

        private void OpenController4WinServiceHost()
        {
            string port = ConfigurationManager.AppSettings[configKeyControllerPort];
            controllerClient = CreateControllerClient("localhost", int.Parse(port));

        }

        private CommonClient<DotNETX.CommonWcfHost.ICommonHostController> CreateControllerClient(string ip, int port)
        {
            System.ServiceModel.Channels.Binding binding = CommonHostController.ControllerBinding;
            EndpointAddress address = new EndpointAddress(CommonHostController.CreateControllerAddress(ip, port));
            CommonClient<DotNETX.CommonWcfHost.ICommonHostController> client = new CommonClient<DotNETX.CommonWcfHost.ICommonHostController>(binding, address);
            return client;
        }

        private ICommonHostController HostController
        {
            get
            {
                return HostInServiceStartedFlag ? controllerClient.Proxy : commonSvcHost;
            }
        }

        private void OpenCommonServiceHost()
        {
            commonSvcHost = new CommonHost();
            commonSvcHost.Opened += (s, e1) => { RefreshServiceState(e1.Name); };
            commonSvcHost.Closed += (s, e1) => { RefreshServiceState(e1.Name); };
            commonSvcHost.Faulted += (s, e1) =>
            {
                RefreshServiceState(e1.Name);
                if (!errCounts.ContainsKey(e1.Name)) errCounts.Add(e1.Name, 0);
                errCounts[e1.Name]++;
                if (errCounts[e1.Name] < MAX_CONTINUAL_ERR_COUNT)
                {
                    new Action(() =>
                    {
                        System.Threading.Thread.Sleep(1000);
                        commonSvcHost.Close(e1.Name);
                        System.Threading.Thread.Sleep(2000);
                        commonSvcHost.Open(e1.Name);
                    }).BeginInvoke(null, null);
                }
                else
                {
                    errCounts[e1.Name] = 0;
                    MessageBox.Show(string.Format("服务[{0}]连续{1}次开启未成功, 停止尝试开启！", e1.Name, MAX_CONTINUAL_ERR_COUNT)); 
                    commonSvcHost.Close(e1.Name);
                }
            };
            string folders = ConfigurationManager.AppSettings[configKeyAssemblyFolders];
            commonSvcHost.SetServiceAssemblyFolders(null == folders ? null : folders.Split(','));
            commonSvcHost.Initial();
        }

        private void LoadServiceList()
        {
            IEnumerable<string> names = HostController.GetServiceNames();
            this.dataGridView1.Rows.Clear();
            foreach (string n in names)
            {
                this.dataGridView1.Rows.Add(n, HostController.GetStatus(n).ToString());
            }
        }

        private void RefreshServiceState(string name)
        {
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                string cellName = row.Cells[0].Value.ToString();
                if (name == cellName)
                {
                    System.ServiceModel.CommunicationState state = HostController.GetStatus(name);
                    row.Cells[1].Value = state.ToString();
                }
            }
        }

        private void RefreshAllServiceState()
        {
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                string name = row.Cells[0].Value.ToString();
                string status = HostController.GetStatus(name).ToString();
                if (status != row.Cells[1].Value.ToString())
                {
                    row.Cells[1].Value = status;
                }
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!exitFlag)
            {
                e.Cancel = true;
                this.Hide();
            }
            else
            {
                if (null != commonSvcHost) commonSvcHost.CloseAll();
                if (null != controllerClient) controllerClient.AbortClose();
            }
        }

        private void MainForm_VisibleChanged(object sender, EventArgs e)
        {
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0) return;
            string name = dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
            if (e.ColumnIndex == 2)
            {
                // 开启
                HostController.Open(name);
                RefreshServiceState(name);
            }
            else if (e.ColumnIndex == 3)
            {
                // 停止
                HostController.Close(name);
                RefreshServiceState(name);
            }
        }

        private void btnAutoStart_Click(object sender, EventArgs e)
        {
            this.toolStripButton1.Checked = !this.toolStripButton1.Checked;
            AutoStartService = this.toolStripButton1.Checked;
        }

        private void btnOpenAll_Click(object sender, EventArgs e)
        {
            HostController.OpenAll();
            RefreshAllServiceState();
        }

        private void btnCloseAll_Click(object sender, EventArgs e)
        {
            HostController.CloseAll();
            RefreshAllServiceState();
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(string.Format("退出[{0}]？", this.Text), "提示", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
            {
                exitFlag = true;
                Close();
            }
        }

        private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                this.Visible = !this.Visible;
            }
        }

        private void 显示主界面ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Show();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            LoadServiceList();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (HostInServiceStartedFlag)
            {
                RefreshAllServiceState();
            }
        }

        // 安装服务
        private void btnInstallWinSvc_Click(object sender, EventArgs e)
        {
            if (HostInServiceInstalledFlag) return;
            try
            {
                string winsvc_file = ConfigurationManager.AppSettings[configKeyWindowsServiceAssemblyFilePath];
                if (!System.IO.File.Exists(winsvc_file))
                {
                    MessageBox.Show(string.Format("无法找到服务程序文件[{0}]，安装服务失败！", winsvc_file), "警告");
                    return;
                }
                System.IO.File.Copy(this.GetType().Assembly.Location + ".config", winsvc_file + ".config", true);
                HostController.CloseAll();
                InstalUtil.InstallService(winsvc_file, serviceName, null);
                InstalUtil.StartService(serviceName);

                btnInstallWinSvc.Visible = false;
                btnUnInstallWinSvc.Visible = true;

                HostInServiceStartedFlag = true;
                object obj = controllerClient.Proxy; //controllerClient.CreateChannel();
                RefreshAllServiceState();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        // 卸载服务
        private void btnUnInstallWinSvc_Click(object sender, EventArgs e)
        {
            if (!HostInServiceInstalledFlag) return;
            try
            {
                string winsvc_file = ConfigurationManager.AppSettings[configKeyWindowsServiceAssemblyFilePath];

                InstalUtil.StopService(serviceName);
                InstalUtil.UnInstallService(winsvc_file, serviceName, null);

                btnInstallWinSvc.Visible = true;
                btnUnInstallWinSvc.Visible = false;

                HostInServiceStartedFlag = false;
                RefreshAllServiceState();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
